#include "../inc/metroline.hpp"
#include "opencv2/highgui.hpp"
#include <cstdio>
#include <iostream>
#include <opencv2/core/mat.hpp>
#include <opencv2/core/types.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv4/opencv2/core/mat.hpp>
#include <opencv4/opencv2/core/types.hpp>
#include <opencv4/opencv2/imgcodecs.hpp>
#include <stdexcept>

const cv::Scalar basic_metro::white = cv::Scalar(0xFF, 0xFF, 0xFF);
const cv::Scalar basic_metro::black = cv::Scalar(0x00, 0x00, 0x00);
const cv::Scalar basic_metro::gray	= cv:::Scalar(0x80, 0x80, 0x80);
const cv::Scalar basic_metro::yellow =
	black;	// cv::Scalar(0xF0, 0xF8, 0xFF); /* 灯下黄改灯下黑 */
cv::Scalar basic_metro::before_light  = cv::Scalar(); /* 绿 */
cv::Scalar basic_metro::passed_light  = cv::Scalar(); /* 红 */
cv::Scalar basic_metro::now_st_light  = cv::Scalar(); /* 黄 */
cv::Scalar basic_metro::section_light = cv::Scalar(); /* 黄 */
cv::Scalar basic_metro::line_color	  = cv::Scalar();

void basic_metro::basic_image() {
	image = cv::Mat::zeros(cv::Size(width, height), CV_8UC3);
	/* 白色背景 */
	cv::rectangle(image, cv::Rect(0, 0, width, height), white, -1, cv::LINE_AA);
	/* 加上底图 */
	if (base_map.empty() == false) {
		int diff = base_map.find_first_of('=');
		int x_pos, y_pos;
		int retval = sscanf(base_map.c_str() + diff, "=(%d,%d)", &x_pos, &y_pos);
		if (retval != 2)
			throw std::invalid_argument(("basemap invalid: " + base_map).c_str());
		base_map		 = base_map.substr(0, diff);
		cv::Mat logo	 = cv::imread(base_map);
		cv::Mat imageROI = image(
			cv::Range(y_pos, y_pos + logo.rows), cv::Range(x_pos, x_pos + logo.cols));
		logo.copyTo(imageROI);
	}
	/* 加上文字 */
	word_on();
	/* 划线，通过的车站标灰色 */
	cv::rectangle(
		image,
		cv::Rect(
			station_begin, height / 2 - line_thick / 2,
			line_length * (station_numbers - 1), line_thick),
		line_color, -1, cv::LINE_AA);
	/* 标记站点和站间闪灯 */
	for (int index = 0; index < station_numbers; index++) {
		const int x_pos = station_begin + index * line_length;
		const int y_pos = height / 2;
		cv::circle(
			image, cv::Point(x_pos, y_pos), station_outer_r, line_color, -1, cv::LINE_AA);
		cv::circle(
			image, cv::Point(x_pos, y_pos), station_inner_r, yellow, -1, cv::LINE_AA);
		/* 标记站间闪灯 */
		if (index < station_numbers - 1) {
			for (int _index = 0; _index < line_point_counter; _index++) {
				cv::circle(
					image, cv::Point(x_pos + line_point_section * (_index + 1), y_pos),
					line_point_outer_r, yellow, -1, cv::LINE_AA);
			}
		}
	}
	/*end for lights*/
	return;
}

void basic_metro::light_on(
	const int  station_passed,
	const bool in_section,
	const bool now_light_on) {
	/* 站点亮灯 */
	for (int index = 0; index < station_numbers; index++) {
		auto	   point = cv::Point(station_begin + index * line_length, height / 2);
		cv::Scalar color;
		if (in_section == true) {
			/* 在车站区间内，只有两种颜色 */
			if (index < station_passed + 1)
				color = passed_light;
			else
				color = before_light;
		}
		else { /* 在车站里，有三种颜色 */
			if (index < station_passed)
				color = passed_light;
			else if (index == station_passed)
				color = now_light_on ? now_st_light : yellow;
			else
				color = before_light;
		}
		cv::circle(_image, point, station_light_point, color, -1, cv::LINE_AA);
	}
	/* 站间亮灯 */
	if (now_light_on == true && in_section == true) {
		for (int index = 0; index < line_point_counter; index++) {
			auto point = cv::Point(
				station_begin + station_passed * line_length +
					(index + 1) * line_point_section,
				height / 2);
			cv::circle(_image, point, line_point_inner_r, section_light, -1, cv::LINE_AA);
		}
	}
}

void basic_metro::word_on() {
	for (int index = 0; index < station_list.size(); index++) {
		str		filename	= "/tmp/zzm/image/" + std::to_string(index + 1) + ".png";
		cv::Mat station_pic = cv::imread(filename);
		// size calc
		int	 x_middle = station_begin + line_length * index;
		int	 y_middle = height / 2;
		bool is_down  = index % 2 == 0;
		int	 x_range  = station_pic.cols;
		int	 y_range  = station_pic.rows;
		int	 x_start  = x_middle - x_range / 2;
		int	 x_end	  = x_start + x_range;
		int	 y_start  = height / 4 - y_range / 2 + 5;
		if (is_down) y_start += height / 2 - 10;
		int y_end = y_start + y_range;
		// draw line
		int y_line = height / 4 - y_range / 2 - 7;
		if (is_down)
			y_line = y_middle + y_line;
		else
			y_line = y_middle - y_line;
		auto p1 = cv::Point(station_begin + line_length * index, y_middle);
		auto p2 = cv::Point(station_begin + line_length * index, y_line);
		auto p3 = cv::Point(x_start, y_line);
		auto p4 = cv::Point(x_end, y_line);
		cv::line(image, p1, p2, line_color, 1, cv::LINE_8);
		cv::line(image, p3, p4, line_color, 1, cv::LINE_AA);
		//  copy
		try{
			cv::Mat imageROI = image(cv::Range(y_start, y_end), cv::Range(x_start, x_end));
			station_pic.copyTo(imageROI);
		} catch (...) {
			throw std::runtime_error("Draw words failed. Maybe the first or last station\'s name is toooooo long. You may use less font size or shorter name.");
		}
	}
}

void basic_metro::param_autogen() {
	/* 车站数量 */
	station_numbers = station_list.size();
	/* 线宽默认13 */
	line_thick = 13;
	if (station_numbers > 28) line_thick = 11;
	/* 车站数量多于10的时候使用1800个像素 */
	if (station_numbers < 10)
		line_length = (width - 120) / 9;
	else
		line_length = (width - 120) / (station_numbers - 1);
	/* 起点居中 */
	station_begin = width / 2 - line_length * (station_numbers - 1) / 2;
	/* 相邻车站具有1-3个光点 */
	line_point_counter = line_length / 20 - 1;
	if (line_point_counter < 1) line_point_counter = 1;
	if (line_point_counter > 3) line_point_counter = 3;
	/* 相邻站点间距 */
	line_point_section = line_length / (line_point_counter + 1);
	/* 光点内外半径 */
	line_point_outer_r = line_thick / 2 - 1;
	line_point_inner_r = line_point_outer_r - 1;
	/* 车站内外半径 */
	station_outer_r		= line_thick / 2 + 1;
	station_inner_r		= station_outer_r - 1;
	station_light_point = station_outer_r - 2;
}
